package cn.jbolt.ai.app.service.impl;


import cn.hutool.core.util.StrUtil;
import cn.jbolt.ai.app.entity.AiAppConfig;
import cn.jbolt.ai.core.chain.node.InnerNodeType;
import cn.jbolt.ai.core.chain.node.action.funccall.FuncCallNodeConfig;
import cn.jbolt.ai.core.chain.node.action.funccall.FuncChatNodeConfig;
import cn.jbolt.ai.core.chain.node.base.AppConfigConstant;
import cn.jbolt.ai.core.chain.node.base.LlmConfig;
import cn.jbolt.ai.core.chain.node.start.StartFromUserInputConfig;
import cn.jbolt.util.JSONUtil;
import cn.jbolt.ai.app.dao.AiAppNodeMapper;
import cn.jbolt.ai.app.entity.AiAppNode;
import cn.jbolt.ai.app.service.AiAppConfigService;
import cn.jbolt.ai.app.service.AiAppNodeService;
import cn.jbolt.util.Result;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.jboltai.event.chain.ChainNode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class AiAppNodeServiceImpl extends ServiceImpl<AiAppNodeMapper, AiAppNode> implements AiAppNodeService {
    private static final Logger logger = LoggerFactory.getLogger(AiAppNodeServiceImpl.class);
    @Autowired
    private AiAppConfigService aiAppConfigService;

    @Override
    public Result<List<AiAppNode>> getNodesByAppId(Long appId) {
        List<AiAppNode> nodes = this.list(new QueryWrapper<AiAppNode>().eq("app_id", appId));
        if (nodes != null) {
            return Result.success(nodes);
        } else {
            return Result.error("节点不存在");
        }
    }

    @Transactional
    public Result deleteNodesByAppId(Long appId) {
        List<AiAppNode> nodes = this.list(new QueryWrapper<AiAppNode>().eq("app_id", appId));
        if (nodes != null && nodes.size() > 0) {
            //清除node节点的时候,也要一同清除节点中的配置
            List<Long> ids = nodes.stream().map(AiAppNode::getId).collect(Collectors.toList());
            boolean remove = this.remove(new QueryWrapper<AiAppNode>().eq("app_id", appId));
            if (remove) {
                Result result = aiAppConfigService.deleteByNodeId(ids);
                if (result.isSuccess()) {
                    return Result.success();
                }
                return result;
            }
            return Result.error("清理旧节点异常");
        }
        return Result.success();
    }

    @Override
    public Result listByPage(Integer page, Integer pageSize) {
        Page<AiAppNode> pageResult = page(new Page<>(page, pageSize));
        return Result.success(pageResult);
    }

    @Override
    public Result add(AiAppNode node) {
        boolean save = save(node);
        if (save) {
            return Result.success(node);
        } else {
            return Result.error("添加失败");
        }
    }

    @Override
    public Result update(AiAppNode node) {
        boolean update = updateById(node);
        if (update) {
            return Result.success(node);
        } else {
            return Result.error("更新失败");
        }
    }

    @Override
    public Result delete(Long id) {
        boolean delete = removeById(id);
        if (delete) {
            return Result.success();
        } else {
            return Result.error("删除失败");
        }
    }

    @Override
    public Result addNodeAfters(Long id, String caseName, Long afterId) {
        AiAppNode nodeDb = getById(id);
        if (nodeDb != null) {
            try {
                if (nodeDb.getAfters() == null || StrUtil.isEmpty(nodeDb.getAfters())) {//之前没有节点
//                     String[] array = new String[] {afterId.toString()};
                    ObjectNode config = JSONUtil.createObjectNode().putPOJO(caseName, new Long[]{afterId});
                    nodeDb.setAfters(config.toString());
                } else {//有节点
                    //把afters变成object对象
                    ObjectNode config = JSONUtil.toJsonObject(nodeDb.getAfters());
                    //获取caseName,这是一个存放数组的
                    ArrayNode caseConfig = (ArrayNode) config.get(caseName);
                    // 如果你需要将其作为 List<String> 来处理
                    if (caseConfig == null) {
                        config.putPOJO(caseName, new Long[]{afterId});
                    } else {
                        for (JsonNode jsonNode : caseConfig) {
                            if (jsonNode.asText().equals(afterId.toString())) {
                                return Result.error("该节点已经存在");
                            }
                        }

                        caseConfig.add(afterId);
                    }
                    nodeDb.setAfters(config.toString());

                }
            } catch (Exception e) {
                e.printStackTrace();
                logger.error("更新失败,afters转换格式异常,原因:{}", e.getMessage());
                return Result.error("更新失败,afters转换格式异常");
            }
            if (updateById(nodeDb)) {
                return Result.success();
            } else {
                return Result.error("更新失败");
            }
        }
        return Result.error("未找到节点");
    }


    @Override
    public Result initAppNodes(Long appId) {
        //先创建6个节点
        List<AiAppNode> nodeList = new ArrayList<>();
        /*开始节点*/
        AiAppNode startNode = new AiAppNode();
        startNode.setType(InnerNodeType.START_FROM_USERINPUT);
        startNode.setAppId(appId);
        nodeList.add(startNode);
        /*function call节点*/
        AiAppNode functionNode = new AiAppNode();
        functionNode.setType(InnerNodeType.FUNC_CALL);
        functionNode.setAppId(appId);
        nodeList.add(functionNode);
        /*chat with function call节点*/
        AiAppNode chatWithFunctionNode = new AiAppNode();
        chatWithFunctionNode.setType(InnerNodeType.FUNC_CHAT);
        chatWithFunctionNode.setAppId(appId);
        nodeList.add(chatWithFunctionNode);
        /*知识库查询节点*/
        AiAppNode klbSearchNode = new AiAppNode();
        klbSearchNode.setType(InnerNodeType.KLB_SEARCH);
        klbSearchNode.setAppId(appId);
        nodeList.add(klbSearchNode);
        /*chat with 知识库查询节点，给匹配到的用*/
        AiAppNode chatWithKlbNode1 = new AiAppNode();
        chatWithKlbNode1.setType(InnerNodeType.KLB_CHAT);
        chatWithKlbNode1.setAppId(appId);
        nodeList.add(chatWithKlbNode1);

        /*chat with 知识库查询节点，给未匹配到的用*/
        AiAppNode chatWithKlbNode2 = new AiAppNode();
        chatWithKlbNode2.setType(InnerNodeType.KLB_CHAT);
        chatWithKlbNode2.setAppId(appId);
        nodeList.add(chatWithKlbNode2);



        saveBatch(nodeList);
        //添加节点的关联关系
        Result result = addNodeAfters(startNode.getId(), ChainNode.AFTER_KEY_SUCCESS, functionNode.getId());
        if (result.isError()) return result;
        result = addNodeAfters(functionNode.getId(), AppConfigConstant.AFTER_KEY_FUNC_CALL_SUCCESS, chatWithFunctionNode.getId());
        if (result.isError()) return result;
        result = addNodeAfters(functionNode.getId(), AppConfigConstant.AFTER_KEY_FUNC_NO_MATCH, klbSearchNode.getId());
        if (result.isError()) return result;
        result = addNodeAfters(klbSearchNode.getId(), AppConfigConstant.AFTER_KEY_KLB_MATCH, chatWithKlbNode1.getId());
        if (result.isError()) return result;
        result = addNodeAfters(klbSearchNode.getId(), AppConfigConstant.AFTER_KEY_KLB_NOMATCH, chatWithKlbNode2.getId());
        if (result.isError()) return result;

        //分别再给节点添加配置
        return initNodeConfig(startNode.getId(), functionNode.getId(),
                chatWithFunctionNode.getId(), klbSearchNode.getId(), chatWithKlbNode1.getId(), chatWithKlbNode2.getId());

    }

    private Result initNodeConfig(Long startNodeId, Long functionNodeId, Long chatWithFunctionNodeId,
                                  Long klbSearchNodeId, Long chatWithKlbNodeId, Long chatWithKlbNode2) {
        List<AiAppConfig> configs = new ArrayList<>();
        AiAppConfig startNodeConfig = new AiAppConfig();

        //开始节点配置
        startNodeConfig.setLinkType(AppConfigConstant.LINK_TYPE_NODE);
        startNodeConfig.setLinkId(startNodeId);
        StartFromUserInputConfig startInputNode = new StartFromUserInputConfig();
        startInputNode.setOutputField("prompt");
        startNodeConfig.setConfigValue(JSONUtil.toJson(startInputNode));
        configs.add(startNodeConfig);

        //FUnction call Node配置
        AiAppConfig functionNodeConfig = new AiAppConfig();
        functionNodeConfig.setLinkType(AppConfigConstant.LINK_TYPE_NODE);
        functionNodeConfig.setLinkId(functionNodeId);
        FuncCallNodeConfig funcCallConfig = new FuncCallNodeConfig();
        funcCallConfig.setResultOutputField("func_call_result");
        funcCallConfig.setMatchFuncOutputField("match_function");

        LlmConfig llmConfig = new LlmConfig();
        llmConfig.setTemperature(0.2);
        llmConfig.setInputField("prompt");
        llmConfig.setUseContext(false);
        llmConfig.setStream(false);

        functionNodeConfig.setConfigValue(
                JSONUtil.toJson(JSONUtil.createObjectNode(AppConfigConstant.CONFIG_TYPE_LLM, llmConfig,
                        AppConfigConstant.CONFIG_TYPE_FUNCCALL, funcCallConfig))
        );
        configs.add(functionNodeConfig);


        //ChatWithFunctionNodeConfig
        AiAppConfig chatWithFunctionNodeConfig = new AiAppConfig();
        chatWithFunctionNodeConfig.setLinkType(AppConfigConstant.LINK_TYPE_NODE);
        chatWithFunctionNodeConfig.setLinkId(chatWithFunctionNodeId);
        llmConfig = new LlmConfig();
        llmConfig.setStream(true);
        llmConfig.setTemperature(null);
        llmConfig.setMaxTokens(null);
//        llmConfig.setInputField("prompt");
        llmConfig.setOutputToResponse(true);
        llmConfig.setPersistDb(true);

        FuncChatNodeConfig funcChatConfig = new FuncChatNodeConfig();
        funcChatConfig.setFuncCallResultField("func_call_result");
        funcChatConfig.setMatchFunctionField("match_function");


        chatWithFunctionNodeConfig.setConfigValue(
                JSONUtil.toJson(JSONUtil.createObjectNode(AppConfigConstant.CONFIG_TYPE_LLM, llmConfig,
                        AppConfigConstant.CONFIG_TYPE_FUNCCHAT, funcChatConfig))
        );
        configs.add(chatWithFunctionNodeConfig);


        //ChatWithKlbNodeConfig
        AiAppConfig chatWithKlbNodeConfig = new AiAppConfig();
        chatWithKlbNodeConfig.setLinkType(AppConfigConstant.LINK_TYPE_NODE);
        chatWithKlbNodeConfig.setLinkId(chatWithKlbNodeId);
        llmConfig = new LlmConfig();
        llmConfig.setStream(true);
        llmConfig.setTemperature(null);
        llmConfig.setMaxTokens(null);
        llmConfig.setUseContext(null);
//        llmConfig.setInputField("prompt");
        llmConfig.setOutputToResponse(true);
        llmConfig.setPersistDb(true);

        chatWithKlbNodeConfig.setConfigValue(
                JSONUtil.toJson(JSONUtil.createObjectNode(AppConfigConstant.CONFIG_TYPE_LLM, llmConfig))
        );
        configs.add(chatWithKlbNodeConfig);


        AiAppConfig chatWithKlbNodeConfig2 = new AiAppConfig();
        chatWithKlbNodeConfig2.setLinkType(AppConfigConstant.LINK_TYPE_NODE);
        chatWithKlbNodeConfig2.setLinkId(chatWithKlbNode2);
        chatWithKlbNodeConfig2.setConfigValue(
                JSONUtil.toJson(JSONUtil.createObjectNode(AppConfigConstant.CONFIG_TYPE_LLM, llmConfig))
        );
        configs.add(chatWithKlbNodeConfig2);

        return aiAppConfigService.addConfigs(configs);

    }


    /**
     * 初始化chatwithfunc call result节点的配置
     *
     * @param nodeId
     */
//    private void initChatWithFuncNodeConfig(Long nodeId) {
//        ObjectNode node = JSONUtil.createObjectNode();
//        node.put(AppConfigConstant.CONFIG_KEY_PROMPT_TPL, AIPrompts.CHAT_WITH_FUNC_RESULT);
//        aiAppConfigService.add(AppConfigConstant.LINK_TYPE_NODE, nodeId,
//                AppConfigConstant.CONFIG_TYPE_LLM, node);
//    }
    @Override
    @Transactional
    public Result delAllNodeByAppId(Long appId) {
        //找到所有的节点
        QueryWrapper<AiAppNode> queryWrapper = new QueryWrapper<AiAppNode>().eq("app_id", appId);
        List<AiAppNode> nodes = list(queryWrapper);
        if (nodes != null) {
            //找到所有节点的id并返回一个node的id数组
            List<Long> nodeIds = nodes.stream().map(AiAppNode::getId).collect(Collectors.toList());
            if(nodeIds.size()>0){
                Result result = aiAppConfigService.deleteByLinkType(AppConfigConstant.LINK_TYPE_NODE, nodeIds);
                if (result.isError()) {
                    return Result.error("删除节点配置失败");
                }
                //移除所有的node
                boolean b = removeByIds(nodeIds);
                if (!b) {
                    return Result.error("删除节点失败");
                }
            }

        }
        return Result.success();
    }

    @Override
    public Result addNodes(List<AiAppNode> nodeList) {
        boolean b = saveBatch(nodeList);
        if (b) {
            return Result.success();
        }

        return Result.error("添加节点失败");
    }

    @Override
    public Result<AiAppNode> getNodeByAppIdAndType(Long appId, String type) {
        QueryWrapper<AiAppNode> queryWrapper = new QueryWrapper<AiAppNode>().eq("app_id", appId).eq("type", type);
        return Result.success(getOne(queryWrapper));

    }

}
